package sg.edu.nus.iss.cerberus.elements;

import java.util.Collection;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ui.IEditorPart;

public abstract class TypeFacade {

	public static enum MethodSearchMode {
		BY_CALL, BY_NAME
	}

	protected final ICompilationUnit compilationUnit;

	public static TypeFacade createFacade(ICompilationUnit compilationUnit) {

		return new ClassTypeFacade(compilationUnit);
	}

	public TypeFacade(ICompilationUnit compilationUnit) {
		this.compilationUnit = compilationUnit;
	}

	public TypeFacade(IFile file) {
		this.compilationUnit = JavaCore.createCompilationUnitFrom(file);
	}

	public TypeFacade(IEditorPart editorPart) {
		IFile file = (IFile) editorPart.getEditorInput()
				.getAdapter(IFile.class);
		this.compilationUnit = JavaCore.createCompilationUnitFrom(file);
	}

	public IType getType() {
		return this.compilationUnit.findPrimaryType();
	}

	public ICompilationUnit getCompilationUnit() {
		return this.compilationUnit;
	}

	protected boolean doesMethodExist(String testMethodName) {
		try {
			IMethod[] vorhandeneTests = this.compilationUnit.findPrimaryType()
					.getMethods();
			for (IMethod method : vorhandeneTests) {
				if (testMethodName.equals(method.getElementName())) {
					return true;
				}
			}
		} catch (JavaModelException exc) {
			exc.printStackTrace();
		}

		return false;
	}

	public IJavaProject getJavaProject() {
		return compilationUnit.getJavaProject();
	}

	/**
	 * Returns one member corresponding to the given method of this type or to
	 * this type (for instance a test method calling the given method if this
	 * type is a class under test, or a method under test called by the given
	 * test method if this type is a test case, or a test case corresponding to
	 * this class, etc...). If there are several resulting members the user has
	 * to make a choice via a dialog. If no member is found <code>null</code> is
	 * returned.
	 * 
	 * @param method
	 *            the method to search for correspondence or <code>null</code>
	 *            to only search based on this type
	 * @param createIfNecessary
	 *            whether to propose the creation of a type if no correspondence
	 *            is found
	 * @param extendedSearch
	 *            whether to also search for method calls (together with search
	 *            by method name)
	 * @param promptText
	 *            the prompt text to display in the dialog asking the user to
	 *            choose for a member
	 * @return one corresponding member or <code>null</code>
	 */

	abstract protected Collection<IMethod> getCorrespondingMethodsInClasses(
			IMethod method, Set<IType> classes);

	abstract protected Set<IType> getCorrespondingClasses();
}
